home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / General / DR1.#1 PowerPlant ƒ / LView.cp < prev    next >
Text File  |  1994-02-10  |  35KB  |  1,398 lines

  1. // ===========================================================================
  2. //    LView.cp                        ©1993 Metrowerks Inc. All rights reserved.
  3. // ===========================================================================
  4. //
  5. //    Abstract class for a Pane which can be larger than its Frame (i.e., it
  6. //    can scroll) and can have SubPanes
  7.  
  8. #include "LView.h"
  9. #include "LList.h"
  10. #include "LListIterator.h"
  11. #include "LStream.h"
  12.  
  13.  
  14. // === Local Constants ===
  15.  
  16. const Int16        max_PortOrigin = 16384;
  17. const Int16        min_PortOrigin = -32768;
  18. const Int32        mask_Lo14Bits = 0x00003FFF;
  19.  
  20.  
  21. // === Class Variables ===
  22.  
  23. LView*    LView::sInFocusView = nil;
  24.  
  25.  
  26. // ---------------------------------------------------------------------------
  27. //        • LView()
  28. // ---------------------------------------------------------------------------
  29. //    Default Constructor
  30.  
  31. LView::LView()
  32. {
  33.     InitView();                        // Initialize to default values
  34. }
  35.  
  36.  
  37. // ---------------------------------------------------------------------------
  38. //        • LView(const LView&)
  39. // ---------------------------------------------------------------------------
  40. //    Copy Constructor
  41. //
  42. //    Does shallow copy; SubPanes are not copied.
  43.  
  44. LView::LView(
  45.     const LView    &inOriginal)
  46.         : LPane(inOriginal)
  47. {
  48.     InitView();                        // Initialize to default values
  49.     
  50.         // Copy members of Original. There's no need to copy mRevealedRect
  51.         // and mUpdateRgnH because they'll be computed when this View
  52.         // is put inside its SuperView.
  53.         
  54.     mImageSize = inOriginal.mImageSize;
  55.     mImageLocation = inOriginal.mImageLocation;
  56.     mScrollUnit = inOriginal.mScrollUnit;
  57.     mPortOrigin = inOriginal.mPortOrigin;
  58.     mReconcileOverhang = inOriginal.mReconcileOverhang;
  59.     }
  60.  
  61.  
  62. // ---------------------------------------------------------------------------
  63. //        • LView(LStream*)
  64. // ---------------------------------------------------------------------------
  65. //    Construct View from data in a Stream
  66.  
  67. LView::LView(
  68.     LStream    *inStream)
  69.         : LPane(inStream)
  70. {
  71.     DataIDT        dataID;
  72.     inStream->ReadData(&dataID, sizeof(DataIDT));
  73.     SignalIf_(dataID != 'View');
  74.     
  75.     InitView();                        // Initialize to default values
  76.  
  77.     SViewInfo    viewInfo;
  78.     inStream->ReadData(&viewInfo, sizeof(SViewInfo));
  79.     
  80.     mImageSize = viewInfo.imageSize;
  81.     mScrollUnit = viewInfo.scrollUnit;
  82.     mReconcileOverhang = viewInfo.reconcileOverhang;
  83.     
  84.     ScrollImageTo(viewInfo.scrollPos.h, viewInfo.scrollPos.v, false);
  85.     CalcRevealedRect();
  86.  
  87.     SetDefaultView(this);
  88. }
  89.  
  90.  
  91. // ---------------------------------------------------------------------------
  92. //        • InitView
  93. // ---------------------------------------------------------------------------
  94. //    Initialize View member variables to default values
  95.  
  96. void
  97. LView::InitView()
  98. {
  99.     mImageSize.width = mFrameSize.width;
  100.     mImageSize.height = mFrameSize.height;
  101.     mImageLocation.h = mImageLocation.v = 0;
  102.     mScrollUnit.h = mScrollUnit.v = 1;
  103.     mPortOrigin.h = mPortOrigin.v = 0;
  104.     mRevealedRect.left =
  105.         mRevealedRect.top =
  106.         mRevealedRect.right =
  107.         mRevealedRect.bottom = 0;
  108.     mUpdateRgnH = NewRgn();
  109.     mReconcileOverhang = false;
  110. }
  111.  
  112.  
  113. // ---------------------------------------------------------------------------
  114. //        • ~LView
  115. // ---------------------------------------------------------------------------
  116. //    Destructor
  117. //
  118.  
  119. LView::~LView()
  120. {
  121.     DeleteAllSubPanes();            // Delete Panes contained by this View
  122.  
  123.     DisposeRgn(mUpdateRgnH);
  124.     
  125.     OutOfFocus(this);                // Don't leave a dangling Focus
  126.     
  127.     if (sDefaultView == this) {
  128.         SetDefaultView(nil);
  129.     }
  130. }
  131.  
  132.  
  133. // ---------------------------------------------------------------------------
  134. //        • FinishCreate
  135. // ---------------------------------------------------------------------------
  136. //    Wrapper function for FinishCreateSelf
  137. //    You will rarely want to override this function
  138. //
  139. //    SubPanes are told to FinishCreateSelf *before* their SuperView.
  140. //    Therefore, a SupverView is assured that all its SubPanes have
  141. //    finished creating when its FinishCreateSelf function gets called.
  142.  
  143. void
  144. LView::FinishCreate()
  145. {
  146.     LListIterator iterator(mSubPanes, iterate_FromStart);
  147.     LPane    *theSub;
  148.     while (iterator.Next(theSub)) {
  149.         theSub->FinishCreate();
  150.     }
  151.     FinishCreateSelf();
  152. }
  153.  
  154.  
  155. void
  156. LView::AddSubPane(
  157.     LPane    *inSub)
  158. {
  159.     SignalIf_(inSub == nil);
  160.     
  161.     mSubPanes.InsertItemsAt(1, index_Last, inSub);
  162.     OrientSubPane(inSub);
  163. }
  164.  
  165.  
  166. void
  167. LView::RemoveSubPane(
  168.     LPane    *inSub)
  169. {
  170.     SignalIf_(inSub == nil);
  171.     
  172.     mSubPanes.Remove(inSub);
  173. }
  174.  
  175.  
  176. void
  177. LView::DeleteAllSubPanes()
  178. {
  179.     LListIterator iterator(mSubPanes, iterate_FromStart);
  180.     LPane    *theSub;
  181.     while (iterator.Next(theSub)) {
  182.         mSubPanes.Remove(theSub);
  183.         delete theSub;
  184.     }
  185. }    
  186.  
  187.  
  188. void
  189. LView::OrientSubPane(
  190.     LPane    *inSub)
  191. {
  192.     if (mEnabled == triState_On) {
  193.         inSub->SuperEnable();
  194.     } else {
  195.         inSub->SuperDisable();
  196.     }
  197.     
  198.     if (mActive == triState_On) {
  199.         inSub->SuperActivate();
  200.     } else {
  201.         inSub->SuperDeactivate();
  202.     }
  203.     
  204.     if (mVisible == triState_On) {
  205.         inSub->SuperShow();
  206.     } else {
  207.         inSub->SuperHide();
  208.     }
  209. }
  210.  
  211.  
  212. LList&
  213. LView::GetSubPanes()
  214. {
  215.     return mSubPanes;
  216. }
  217.  
  218.  
  219. void
  220. LView::GetImageSize(
  221.     SDimension32    &outSize)        // +++ possible inline
  222. {
  223.     outSize = mImageSize;
  224. }
  225.  
  226.  
  227. void
  228. LView::GetImageLocation(
  229.     SPoint32    &outLocation)        // +++ possible inline
  230. {
  231.     outLocation = mImageLocation;
  232. }
  233.  
  234.  
  235. void
  236. LView::GetScrollPosition(
  237.     SPoint32    &outScrollPosition)
  238. {
  239.     outScrollPosition.h = mFrameLocation.h - mImageLocation.h;
  240.     outScrollPosition.v = mFrameLocation.v - mImageLocation.v;
  241. }
  242.  
  243.  
  244. void
  245. LView::GetRevealedRect(
  246.     Rect    &outRect)                // +++ possible inline
  247. {
  248.     outRect = mRevealedRect;
  249. }
  250.  
  251.  
  252. // ---------------------------------------------------------------------------
  253. //        • CalcRevealedRect
  254. // ---------------------------------------------------------------------------
  255. //    Calculate the portion of the Frame which is revealed through the
  256. //    Frames of all SuperViews. RevealedRect is in Port coordinates.
  257.  
  258. void
  259. LView::CalcRevealedRect()
  260. {
  261.                                     // Start with the Frame
  262.     if (CalcPortFrameRect(mRevealedRect)) {
  263.                                     // Frame is in QD Space
  264.         if (mSuperView != nil) {    // Intersect Frame with RevealedRect
  265.                                     //   of SuperView
  266.             Rect    superRevealed;
  267.             mSuperView->GetRevealedRect(superRevealed);
  268.             SectRect(&superRevealed, &mRevealedRect, &mRevealedRect);
  269.         }
  270.         
  271.     } else {                        // Frame not in QD Space
  272.         mRevealedRect.left =        //   so RevealedRect is empty
  273.             mRevealedRect.top =
  274.             mRevealedRect.right =
  275.             mRevealedRect.bottom = 0;
  276.     }
  277. }
  278.  
  279.  
  280. // ---------------------------------------------------------------------------
  281. //        • CalcPortOrigin
  282. // ---------------------------------------------------------------------------
  283. //    Calculate the coordinate origin for the Port needed to set up the
  284. //    Local coordinates of a View
  285. //
  286. //    The Port origin must be in 16-bit space. In fact, the limitation is more
  287. //    restrictive because the entire Port must be in 16-bit space. The origin
  288. //    is the top left corner. To make sure that the bottom right corner is
  289. //    in 16-bit space, we force the origin to be less than 2^14 (16,384),
  290. //    which allows Port dimensions of a maximum of 16,384 pixels. At 72 dpi,
  291. //    this is about 227 inches or 19 feet (much more screen or printer area
  292. //    than you can get with current technology).
  293. //
  294. //    This means that Local and Image coordinates will be the same when the
  295. //    Image size is less than 16,384 pixels. For Images greater than this,
  296. //    you can't use absolute coordinates for drawing. You need to offset
  297. //    the coordinates using ImageToLocalPt() and LocalToImagePt().
  298. //
  299. //    The true coordinates offset is the distance between the top left corners
  300. //    of the Image and the Port. If this offset is greater than 2^14, we
  301. //    use an effective offset that is the true offset modulo 2^14:
  302. //        effective_offset = true_offset modulo 2^14
  303. //    Using this effective offset maintains the bit-wise alignment of the Port
  304. //    with respect to base-2 byte boundaries. This is important for drawing
  305. //    Toolbox Patterns and PixPats, as well as for CopyBits calls.
  306.  
  307. void
  308. LView::CalcPortOrigin()
  309. {
  310.     Int32    coord = -mImageLocation.h;
  311.     if (coord > max_PortOrigin) {    // coord is too big
  312.         coord &= mask_Lo14Bits;        // use coord modulo 2^14
  313.     } else if (coord < min_PortOrigin) {
  314.         coord = min_PortOrigin;        // coord is too small, limit to minimum
  315.     }
  316.     mPortOrigin.h = coord;
  317.     
  318.     coord = -mImageLocation.v;
  319.     if (coord > max_PortOrigin) {
  320.         coord &= mask_Lo14Bits;
  321.     } else if (coord < min_PortOrigin) {
  322.         coord = min_PortOrigin;
  323.     }
  324.     mPortOrigin.v = coord;
  325. }
  326.  
  327.  
  328. RgnHandle
  329. LView::GetLocalUpdateRgn()
  330. {
  331.                                     // Copy update region, which is in port
  332.                                     //   coordinates
  333.     RgnHandle    localUpdateRgnH = NewRgn();
  334.     CopyRgn(mUpdateRgnH, localUpdateRgnH);
  335.     
  336.                                     // Offset copy into local coordinates
  337.     Point    localOffset = {0, 0};
  338.     PortToLocalPoint(localOffset);
  339.     OffsetRgn(localUpdateRgnH, localOffset.h, localOffset.v);
  340.                                     
  341.     return localUpdateRgnH;            // Return copy, caller must dispose it
  342. }
  343.  
  344.  
  345. RgnHandle
  346. LView::GetUpdateRgn()
  347. {
  348.     return mUpdateRgnH;
  349. }
  350.  
  351.  
  352. void
  353. LView::SetReconcileOverhang(
  354.     Boolean    inSetting)
  355. {
  356.     mReconcileOverhang = inSetting;
  357. }
  358.  
  359.  
  360. // ---------------------------------------------------------------------------
  361. //        • ResizeFrameBy
  362. // ---------------------------------------------------------------------------
  363. //    Change the Frame size by the specified amounts
  364. //
  365. //        inWidthDelta and inHeightDelta specify, in pixels, how much larger
  366. //        to make the Frame. Positive deltas increase the size, negative deltas
  367. //        reduce the size.
  368.  
  369. void
  370. LView::ResizeFrameBy(
  371.     Int16        inWidthDelta,
  372.     Int16        inHeightDelta,
  373.     Boolean        inRefresh)
  374. {
  375.     LPane::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
  376.  
  377.     CalcRevealedRect();
  378.     OutOfFocus(this);
  379.         
  380.     LListIterator iterator(mSubPanes, iterate_FromStart);
  381.     LPane    *theSub;
  382.     while (iterator.Next(theSub)) {
  383.         theSub->AdaptToSuperFrameSize(inWidthDelta, inHeightDelta, inRefresh);
  384.     }
  385.     
  386.     ReconcileFrameAndImage(inRefresh);
  387. }
  388.  
  389.  
  390. // ---------------------------------------------------------------------------
  391. //        • MoveBy
  392. // ---------------------------------------------------------------------------
  393. //    Move the location of the Image and Frame by the specified amounts
  394. //
  395. //        inHorizDelta and inVertDelta specify, in pixels, how far to move the
  396. //        Frame (within its surrounding Image). Positive horiz deltas move to
  397. //        the left, negative to the right. Positive vert deltas move down,
  398. //        negative up.
  399.  
  400. void
  401. LView::MoveBy(
  402.     Int32        inHorizDelta,
  403.     Int32        inVertDelta,
  404.     Boolean        inRefresh)
  405. {
  406.     if (inRefresh) {
  407.         Refresh();
  408.     }
  409.  
  410.     mImageLocation.h += inHorizDelta;
  411.     mImageLocation.v += inVertDelta;
  412.     
  413.     mFrameLocation.h += inHorizDelta;
  414.     mFrameLocation.v += inVertDelta;
  415.     
  416.     CalcPortOrigin();
  417.     CalcRevealedRect();
  418.     OutOfFocus(this);
  419.     
  420.     if (inRefresh) {
  421.         Refresh();
  422.     }
  423.     
  424.     LListIterator iterator(mSubPanes, iterate_FromStart);
  425.     LPane    *theSub;
  426.     while (iterator.Next(theSub)) {
  427.         theSub->MoveBy(inHorizDelta, inVertDelta, false);
  428.     }
  429. }
  430.  
  431.  
  432. void
  433. LView::SavePlace(
  434.     LStream        *outPlace)
  435. {
  436.     LPane::SavePlace(outPlace);
  437.     
  438.     outPlace->WriteData(&mImageLocation, sizeof(SPoint32));
  439. }
  440.  
  441.  
  442. void
  443. LView::RestorePlace(
  444.     LStream        *inPlace)
  445. {
  446.     LPane::RestorePlace(inPlace);
  447.  
  448.     inPlace->ReadData(&mImageLocation, sizeof(SDimension32));
  449.     CalcPortOrigin();
  450.     CalcRevealedRect();
  451. }
  452.  
  453.  
  454. void
  455. LView::AdaptToNewSurroundings()
  456. {
  457.     CalcRevealedRect();
  458.  
  459.     LListIterator iterator(mSubPanes, iterate_FromStart);
  460.     LPane    *theSub;
  461.     while (iterator.Next(theSub)) {
  462.         theSub->AdaptToNewSurroundings();
  463.     }
  464. }
  465.  
  466.  
  467. // ---------------------------------------------------------------------------
  468. //        • AdaptToSuperFrameSize
  469. // ---------------------------------------------------------------------------
  470. //    Adjust state of View when size of SuperView's Frame changes by the
  471. //    specified amounts
  472.  
  473. void
  474. LView::AdaptToSuperFrameSize(
  475.     Int32    inSurrWidthDelta,            // Change in width of SuperView
  476.     Int32    inSurrHeightDelta,            // Change in height of SuperView
  477.     Boolean    inRefresh)
  478. {
  479.     LPane::AdaptToSuperFrameSize(inSurrWidthDelta, inSurrHeightDelta,
  480.                                     inRefresh);
  481.     AdaptToNewSurroundings();
  482. }
  483.  
  484.  
  485. void
  486. LView::Show()
  487. {
  488.     LPane::Show();
  489.     LListIterator iterator(mSubPanes, iterate_FromStart);
  490.     LPane    *theSub;
  491.     while (iterator.Next(theSub)) {
  492.         theSub->SuperShow();
  493.     }
  494. }
  495.  
  496.  
  497. void
  498. LView::SuperShow()
  499. {
  500.     LPane::SuperShow();
  501.     LListIterator iterator(mSubPanes, iterate_FromStart);
  502.     LPane    *theSub;
  503.     while (iterator.Next(theSub)) {
  504.         theSub->SuperShow();
  505.     }
  506. }
  507.  
  508.  
  509. void
  510. LView::Hide()
  511. {
  512.     LListIterator iterator(mSubPanes, iterate_FromStart);
  513.     LPane    *theSub;
  514.     while (iterator.Next(theSub)) {
  515.         theSub->SuperHide();
  516.     }
  517.     LPane::Hide();
  518. }
  519.  
  520.  
  521. void
  522. LView::SuperHide()
  523. {
  524.     LListIterator iterator(mSubPanes, iterate_FromStart);
  525.     LPane    *theSub;
  526.     while (iterator.Next(theSub)) {
  527.         theSub->SuperHide();
  528.     }
  529.     LPane::SuperHide();
  530. }
  531.  
  532.  
  533. void
  534. LView::Activate()
  535. {
  536.     LPane::Activate();
  537.     LListIterator iterator(mSubPanes, iterate_FromStart);
  538.     LPane    *theSub;
  539.     while (iterator.Next(theSub)) {
  540.         theSub->SuperActivate();
  541.     }
  542. }
  543.  
  544.  
  545. void
  546. LView::SuperActivate()
  547. {
  548.     LPane::SuperActivate();
  549.     LListIterator iterator(mSubPanes, iterate_FromStart);
  550.     LPane    *theSub;
  551.     while (iterator.Next(theSub)) {
  552.         theSub->SuperActivate();
  553.     }
  554. }
  555.  
  556.  
  557. void
  558. LView::Deactivate()
  559. {
  560.     LListIterator iterator(mSubPanes, iterate_FromStart);
  561.     LPane    *theSub;
  562.     while (iterator.Next(theSub)) {
  563.         theSub->SuperDeactivate();
  564.     }
  565.     LPane::Deactivate();
  566. }
  567.  
  568.  
  569. void
  570. LView::SuperDeactivate()
  571. {
  572.     LListIterator iterator(mSubPanes, iterate_FromStart);
  573.     LPane    *theSub;
  574.     while (iterator.Next(theSub)) {
  575.         theSub->SuperDeactivate();
  576.     }
  577.     LPane::SuperDeactivate();
  578. }
  579.  
  580.  
  581. void
  582. LView::Enable()
  583. {
  584.     LPane::Enable();
  585.     LListIterator iterator(mSubPanes, iterate_FromStart);
  586.     LPane    *theSub;
  587.     while (iterator.Next(theSub)) {
  588.         theSub->SuperEnable();
  589.     }
  590. }
  591.  
  592.  
  593. void
  594. LView::SuperEnable()
  595. {
  596.     LPane::SuperEnable();
  597.     LListIterator iterator(mSubPanes, iterate_FromStart);
  598.     LPane    *theSub;
  599.     while (iterator.Next(theSub)) {
  600.         theSub->SuperEnable();
  601.     }
  602. }
  603.  
  604.  
  605. void
  606. LView::Disable()
  607. {
  608.     LListIterator iterator(mSubPanes, iterate_FromStart);
  609.     LPane    *theSub;
  610.     while (iterator.Next(theSub)) {
  611.         theSub->SuperDisable();
  612.     }
  613.     LPane::Disable();
  614. }
  615.  
  616.  
  617. void
  618. LView::SuperDisable()
  619. {
  620.     LListIterator iterator(mSubPanes, iterate_FromStart);
  621.     LPane    *theSub;
  622.     while (iterator.Next(theSub)) {
  623.         theSub->SuperDisable();
  624.     }
  625.     LPane::SuperDisable();
  626. }
  627.  
  628.  
  629. void
  630. LView::EstablishPort()
  631. {
  632.     if (mSuperView != nil) {
  633.         mSuperView->EstablishPort();
  634.     }
  635. }
  636.  
  637.  
  638. // ---------------------------------------------------------------------------
  639. //        • FocusDraw
  640. // ---------------------------------------------------------------------------
  641. //    Prepare for drawing in the View by setting the Port and clipping area
  642. //
  643. //    Returns true if the View is focused
  644. //    Returns false if the View could not be focused
  645. //        This happens when no part of the View is revealed (which means
  646. //        that the clipping area would be empty) or if drawing is locked.
  647. //
  648. //    If FocusDraw returns true, it also means that the View's Frame is
  649. //    in QuickDraw space. The Revealed area would be empty if the Frame
  650. //    did not intersect the Port rectangle (which is always in QuickDraw
  651. //    space) of the Mac Port containing the View.
  652.  
  653. Boolean
  654. LView::FocusDraw()
  655. {
  656.     Boolean    focused = (mLockLevel >= 0);
  657.     
  658.                                     // Skip if already in focus or
  659.                                     //   drawing is locked
  660.     if ( (this != sInFocusView) && focused ) {
  661.         focused = false;
  662.                                     // Don't focus if no part of View
  663.                                     //   Frame is revealed
  664.         if (mRevealedRect.left < mRevealedRect.right) {
  665.             EstablishPort();        // Set current Mac Port
  666.                                     // Set up local coordinate system
  667.             SetOrigin(mPortOrigin.h, mPortOrigin.v);
  668.                                     // Clip to revealed area of View
  669.             Rect    clippingRect = mRevealedRect;
  670.             PortToLocalPoint(topLeft(clippingRect));
  671.             PortToLocalPoint(botRight(clippingRect));
  672.             ClipRect(&clippingRect);
  673.             sInFocusView = this;    // Cache current Focus
  674.             focused = true;
  675.         }
  676.     }
  677.     
  678.     return focused;
  679. }
  680.  
  681.  
  682. // ---------------------------------------------------------------------------
  683. //        • OutOfFocus [static]
  684. // ---------------------------------------------------------------------------
  685. //    Notify View system that a View is no longer in focus
  686. //
  687. //    Call when the coordinate system or clipping region of a View changes,
  688. //    passing a pointer to that View. This clears the saved focus if that
  689. //    View was the one in focus.
  690. //
  691. //    Use nil for inView if you manually change (and don't restore) the
  692. //    current port or clipping region
  693.  
  694. void
  695. LView::OutOfFocus(
  696.     LView    *inView)
  697. {
  698.     if ( (inView == nil) || (sInFocusView == inView) ) {
  699.         sInFocusView = nil;
  700.     }
  701. }
  702.  
  703.  
  704. // ---------------------------------------------------------------------------
  705. //        • Draw
  706. // ---------------------------------------------------------------------------
  707. //    Draw a View and all its SubPanes
  708. //
  709. //    inSuperDrawRgnH specifies, in Port coordinates, the portion of the
  710. //    View's SuperView that needs to be drawn. Specify nil to draw the
  711. //    entire View.
  712.  
  713. void
  714. LView::Draw(
  715.     RgnHandle    inSuperDrawRgnH)
  716. {
  717.                                     // Don't draw if invisible or unable
  718.                                     //   to put in focus
  719.     if (IsVisible() && FocusDraw()) {
  720.                                     // Area of this View to draw is the
  721.                                     //   intersection of inSuperDrawRgnH
  722.                                     //   with the Revealed area of this View
  723.         RectRgn(mUpdateRgnH, &mRevealedRect);
  724.         if (inSuperDrawRgnH != nil) {
  725.             SectRgn(inSuperDrawRgnH, mUpdateRgnH, mUpdateRgnH);
  726.         }
  727.         if (!EmptyRgn(mUpdateRgnH)) {
  728.                                     // Some portion needs to be drawn
  729.             DrawSelf();                // A View is visually behind its
  730.                                     //   SubPanes so it draws itself first,
  731.                                     //   then its SubPanes
  732.             LListIterator iterator(mSubPanes, iterate_FromStart);
  733.             LPane    *theSub;
  734.             while (iterator.Next(theSub)) {
  735.                 theSub->Draw(mUpdateRgnH);
  736.             }
  737.         }
  738.         SetEmptyRgn(mUpdateRgnH);    // Emptying update region frees up memory
  739.                                     //   if this region wasn't rectangular
  740.     }
  741. }
  742.  
  743.  
  744. // ---------------------------------------------------------------------------
  745. //        • CountPanels
  746. // ---------------------------------------------------------------------------
  747. //    Return the number of horizontal and vertical Panels. A Panel is a
  748. //    "frameful" of a View's Image.
  749.  
  750. void
  751. LView::CountPanels(
  752.     Uint32    &outHorizPanels,
  753.     Uint32    &outVertPanels)
  754. {
  755.     SDimension32    imageSize;
  756.     GetImageSize(imageSize);
  757.     
  758.     SDimension16    frameSize;
  759.     GetFrameSize(frameSize);
  760.     
  761.     outHorizPanels = 1;
  762.     if (frameSize.width > 0  &&  imageSize.width > 0) {
  763.         outHorizPanels = ((imageSize.width - 1) / frameSize.width) + 1;
  764.     }
  765.     
  766.     outVertPanels = 1;
  767.     if (frameSize.height > 0  &&  imageSize.height > 0) {
  768.         outVertPanels = ((imageSize.height - 1) / frameSize.height) + 1;
  769.     }
  770. }
  771.  
  772.  
  773. // ---------------------------------------------------------------------------
  774. //        • PrintPanel
  775. // ---------------------------------------------------------------------------
  776. //    Try to Print a Panel of a View
  777. //
  778. //    The View is at the top level of the Printout, meaning that it controls
  779. //    pagination. This functions scrolls the View to the specified panel.
  780.  
  781. void
  782. LView::PrintPanel(
  783.     const PanelSpec    &inPanel,
  784.     RgnHandle        inSuperPrintRgnH)
  785. {
  786.                                     // Don't print if invisible
  787.     if (IsVisible()) {
  788.                                     // Area of this View to print is the
  789.                                     //   intersection of inSuperPrintRgnH
  790.                                     //   with the Revealed area of this View
  791.         RectRgn(mUpdateRgnH, &mRevealedRect);
  792.         if (inSuperPrintRgnH != nil) {
  793.             SectRgn(inSuperPrintRgnH, mUpdateRgnH, mUpdateRgnH);
  794.         }
  795.         
  796.         if ( !EmptyRgn(mUpdateRgnH) &&
  797.              ScrollToPanel(inPanel) &&
  798.              FocusDraw()) {
  799.                                     // Some portion needs to be printed
  800.             PrintPanelSelf(inPanel);
  801.             
  802.                                     // Let SubPanes print within this
  803.                                     //   Panel of its SuperView
  804.             LListIterator iterator(mSubPanes, iterate_FromStart);
  805.             LPane    *theSub;
  806.             while (iterator.Next(theSub)) {
  807.                 theSub->SuperPrintPanel(inPanel, mUpdateRgnH);
  808.             }
  809.         }
  810.         SetEmptyRgn(mUpdateRgnH);    // Emptying update region frees up memory
  811.                                     //   if this region wasn't rectangular
  812.     }
  813. }
  814.  
  815.  
  816. // ---------------------------------------------------------------------------
  817. //        • SuperPrintPanel
  818. // ---------------------------------------------------------------------------
  819. //    SuperView is printing a panel
  820. //
  821. //    The View is not in control of pagination. In general, it is not clear
  822. //    how to print nested scrolling views. This function just prints the
  823. //    View at its current location, without scrolling to a particular panel.
  824.  
  825. void
  826. LView::SuperPrintPanel(
  827.     const PanelSpec    &inSuperPanel,
  828.     RgnHandle        inSuperPrintRgnH)
  829. {
  830.                                     // Don't print if invisible
  831.     if (IsVisible()) {
  832.                                     // Area of this View to print is the
  833.                                     //   intersection of inSuperPrintRgnH
  834.                                     //   with the Revealed area of this View
  835.         RectRgn(mUpdateRgnH, &mRevealedRect);
  836.         if (inSuperPrintRgnH != nil) {
  837.             SectRgn(inSuperPrintRgnH, mUpdateRgnH, mUpdateRgnH);
  838.         }
  839.         
  840.         if ( !EmptyRgn(mUpdateRgnH) && FocusDraw()) {
  841.                                     // Some portion needs to be printed
  842.             PrintPanelSelf(inSuperPanel);
  843.             LListIterator iterator(mSubPanes, iterate_FromStart);
  844.             LPane    *theSub;
  845.             while (iterator.Next(theSub)) {
  846.                 theSub->SuperPrintPanel(inSuperPanel, mUpdateRgnH);
  847.             }
  848.         }
  849.         SetEmptyRgn(mUpdateRgnH);    // Emptying update region frees up memory
  850.                                     //   if this region wasn't rectangular
  851.     }
  852. }
  853.  
  854.  
  855. // ---------------------------------------------------------------------------
  856. //        • ScrollToPanel
  857. // ---------------------------------------------------------------------------
  858. //    Scroll View Image to the specified Panel
  859. //
  860. //    Return whether the specified Panel exists. If it doesn't, View is
  861. //    not scrolled.
  862.  
  863. Boolean
  864. LView::ScrollToPanel(
  865.     const PanelSpec    &inPanel)
  866. {
  867.     Boolean    panelInImage = false;
  868.     
  869.     SDimension16    frameSize;
  870.     GetFrameSize(frameSize);
  871.     
  872.     Uint32    horizPanelCount;
  873.     Uint32    vertPanelCount;
  874.     CountPanels(horizPanelCount, vertPanelCount);
  875.     
  876.     if ((inPanel.horizIndex <= horizPanelCount) &&
  877.         (inPanel.vertIndex <= vertPanelCount)) {
  878.         Int32 horizPos = frameSize.width * (inPanel.horizIndex - 1);
  879.         Int32 vertPos = frameSize.height * (inPanel.vertIndex - 1);
  880.         ScrollImageTo(horizPos, vertPos, false);
  881.         panelInImage = true;
  882.     }
  883.     
  884.     return panelInImage;
  885. }
  886.  
  887.  
  888. void
  889. LView::ScrollImageTo(
  890.     Int32        inLeftLocation,
  891.     Int32        inTopLocation,
  892.     Boolean        inRefresh)
  893. {
  894.     ScrollImageBy(mImageLocation.h - mFrameLocation.h + inLeftLocation,
  895.                   mImageLocation.v - mFrameLocation.v + inTopLocation,
  896.                   inRefresh);
  897. }
  898.  
  899.  
  900. // ---------------------------------------------------------------------------
  901. //        • ScrollImageBy
  902. // ---------------------------------------------------------------------------
  903. //    Scroll Image by specified horizontal and vertical increments
  904. //
  905. //    Scrolling moves the Image relative to the Frame and Port, so that a
  906. //    different portion of the Image is visible thru the Frame.
  907. //
  908. //    Positive deltas scroll right and down.
  909. //    Negative deltas scroll left and up.
  910. //
  911. //    If inRefresh is true, the Port containing the View is updated
  912. //    immediately, rather than refreshed at the next update event.
  913. //    Scrolling usually happens during mouse down tracking, so we want
  914. //    immediate visual feedback.
  915.  
  916. void
  917. LView::ScrollImageBy(
  918.     Int32        inLeftDelta,            // Pixels to scroll horizontally
  919.     Int32        inTopDelta,                // Pixels to scroll vertically
  920.     Boolean        inRefresh)
  921. {
  922.     if (inRefresh) {
  923.     
  924.             // Check if any portion of what is visible now will be
  925.             // visible after the scroll. If so, it should be faster
  926.             // to move the bits rather than redrawing them.
  927.             
  928.         Int32    absLeftDelta = inLeftDelta;
  929.         if (absLeftDelta < 0) {
  930.             absLeftDelta = -absLeftDelta;
  931.         }
  932.         Int32    absTopDelta = inTopDelta;
  933.         if (absTopDelta < 0) {
  934.             absTopDelta = -absTopDelta;
  935.         }
  936.         
  937.         if ( (absLeftDelta < (mRevealedRect.right - mRevealedRect.left)) &&
  938.              (absTopDelta < (mRevealedRect.bottom - mRevealedRect.top)) ) {
  939.             ScrollBits(inLeftDelta, inTopDelta);
  940.         } else {
  941.             Refresh();
  942.         }
  943.     }
  944.  
  945.     mImageLocation.h -= inLeftDelta;    // Move Image
  946.     mImageLocation.v -= inTopDelta;
  947.     CalcPortOrigin();
  948.     OutOfFocus(this);
  949.     
  950.     LListIterator iterator(mSubPanes, iterate_FromStart);
  951.     LPane    *theSub;
  952.     while (iterator.Next(theSub)) {
  953.         theSub->AdaptToSuperScroll(inLeftDelta, inTopDelta);
  954.     }
  955.     
  956.     if (mSuperView != nil) {
  957.         mSuperView->SubImageChanged(this);
  958.     }
  959.  
  960.     if (inRefresh) {
  961.         UpdatePort();
  962.     }
  963. }
  964.  
  965.  
  966. void
  967. LView::ScrollBits(
  968.     Int32        inLeftDelta,            // Pixels to scroll horizontally
  969.     Int32        inTopDelta)                // Pixels to scroll vertically
  970. {
  971.     if (FocusDraw()) {
  972.         Rect    frame = mRevealedRect;
  973.         PortToLocalPoint(topLeft(frame));
  974.         PortToLocalPoint(botRight(frame));
  975.         RgnHandle    updateRgnH = NewRgn();
  976.         ScrollRect(&frame, -inLeftDelta, -inTopDelta, updateRgnH);
  977.         InvalRgn(updateRgnH);            // ??? Use InvalPaneRgn, but
  978.                                         // have to offset updateRgnH to
  979.                                         // Port coords.
  980.         DisposeRgn(updateRgnH);
  981.     }
  982. }
  983.  
  984.  
  985. Boolean
  986. LView::AutoScrollImage(
  987.     Point    inLocalPt)
  988. {
  989.     Boolean    scrolled = false;
  990.     Rect    frame;
  991.     CalcLocalFrameRect(frame);
  992.     
  993.     Int32    horizScroll = 0;
  994.     if (inLocalPt.h < frame.left) {
  995.                                     // AutoScroll left
  996.         Int32    leftMax = mFrameLocation.h - mImageLocation.h;
  997.         if (leftMax > 0) {
  998.             horizScroll = -mScrollUnit.h;
  999.             if (leftMax < mScrollUnit.h) {
  1000.                 horizScroll = -leftMax;
  1001.             }
  1002.         }
  1003.     
  1004.     } else if (inLocalPt.h > frame.right) {
  1005.                                     // AutoScroll right
  1006.         Int32    rightMax = mImageSize.width - mFrameSize.width -
  1007.                             (mFrameLocation.h - mImageLocation.h);
  1008.         if (rightMax > 0) {
  1009.             horizScroll = mScrollUnit.h;
  1010.             if (rightMax < horizScroll) {
  1011.                 horizScroll = rightMax;
  1012.             }
  1013.         }
  1014.     }
  1015.     
  1016.     Int32    vertScroll = 0;
  1017.     if (inLocalPt.v < frame.top) {
  1018.                                     // AutoScroll up
  1019.         Int32    upMax = mFrameLocation.v - mImageLocation.v;
  1020.         if (upMax > 0) {
  1021.             vertScroll = -mScrollUnit.v;
  1022.             if (upMax < mScrollUnit.v) {
  1023.                 vertScroll = -upMax;
  1024.             }
  1025.         }
  1026.                                     
  1027.     } else if (inLocalPt.v > frame.bottom) {
  1028.                                     // AutoScroll down
  1029.         Int32    downMax = mImageSize.height - mFrameSize.height -
  1030.                             (mFrameLocation.v - mImageLocation.v);
  1031.         if (downMax > 0) {
  1032.             vertScroll = mScrollUnit.v;
  1033.             if (downMax < vertScroll) {
  1034.                 vertScroll = downMax;
  1035.             }
  1036.         }
  1037.     }
  1038.     
  1039.     if ((horizScroll != 0) || (vertScroll != 0)) {
  1040.         ScrollImageBy(horizScroll, vertScroll, true);
  1041.         scrolled = true;
  1042.     }
  1043.     
  1044.     return scrolled;
  1045. }
  1046.  
  1047.  
  1048. void
  1049. LView::ResizeImageTo(
  1050.     Int32        inWidth,
  1051.     Int32        inHeight,
  1052.     Boolean        inRefresh)
  1053. {
  1054.     ResizeImageBy(inWidth - mImageSize.width,
  1055.                   inHeight - mImageSize.height,
  1056.                   inRefresh);
  1057. }
  1058.  
  1059.  
  1060. void
  1061. LView::ResizeImageBy(
  1062.     Int32        inWidthDelta,
  1063.     Int32        inHeightDelta,
  1064.     Boolean        inRefresh)
  1065. {
  1066.     mImageSize.width += inWidthDelta;
  1067.     mImageSize.height += inHeightDelta;
  1068.     
  1069.     ReconcileFrameAndImage(inRefresh);
  1070.     
  1071.     if (mSuperView != nil) {
  1072.         mSuperView->SubImageChanged(this);
  1073.     }
  1074. }
  1075.  
  1076.  
  1077. // ---------------------------------------------------------------------------
  1078. //        • ReconcileFrameAndImage
  1079. // ---------------------------------------------------------------------------
  1080. //    Adjusts the Image so that it fits within the Frame
  1081. //
  1082. //    This function addresses the problem of what to do when you scroll a
  1083. //    View to at or near the bottom or right, then make the View's Frame
  1084. //    larger. This would normally expose some "undefined" area below or
  1085. //    to the right of the Image.
  1086. //
  1087. //    If mReconcileOverhang is true, this function scrolls the Image so that
  1088. //    the bottom right corner is at the bottom right of the Frame. However,
  1089. //    it never moves the top left corner of the Image beyond the top left
  1090. //    of the Frame. Therefore, the only time "undefined" area is exposed is
  1091. //    when the Frame is larger than the Image.
  1092. //
  1093. //    For Views with fixed Image sizes, such as drawings where the Image size
  1094. //    is the size of a printed page, set mReconcileOverhang to true. The user
  1095. //    does not normally want to see past the bottom or right of such Views.
  1096. //
  1097. //    For Views with variable Image sizes, such as text blocks where the size
  1098. //    of the Image depends on the number of lines of text, set
  1099. //    mReconcileOverhang to false. The user may want to see the undefined
  1100. //    area in anticipation of the Image growing.
  1101.  
  1102. void
  1103. LView::ReconcileFrameAndImage(
  1104.     Boolean    inRefresh)
  1105. {
  1106.     if (mReconcileOverhang) {
  1107.         SPoint32    currScrollPos;
  1108.         GetScrollPosition(currScrollPos);
  1109.         SPoint32    newScrollPos = currScrollPos;
  1110.     
  1111.                                     // Reconcile Vertical position
  1112.         if ( (mFrameLocation.v + mFrameSize.height) > 
  1113.              (mImageLocation.v + mImageSize.height) ) {
  1114.                                     // Frame extends below Image
  1115.              newScrollPos.v = mImageSize.height - mFrameSize.height;
  1116.              if (newScrollPos.v < 0) {
  1117.                  newScrollPos.v = 0;
  1118.              }
  1119.                                      // Force newScrollPos to be a multiple
  1120.                                      //   of mScrollUnit
  1121.              newScrollPos.v = mScrollUnit.v * 
  1122.                      ((newScrollPos.v + mScrollUnit.v - 1) / mScrollUnit.v);
  1123.              
  1124.         }
  1125.     
  1126.                                     // Reconcile horizontal position
  1127.         if ( (mFrameLocation.h + mFrameSize.width) > 
  1128.              (mImageLocation.h + mImageSize.width) ) {
  1129.                                     // Frame extends right Image
  1130.              newScrollPos.h = mImageSize.width - mFrameSize.width;
  1131.              if (newScrollPos.h < 0) {
  1132.                  newScrollPos.h = 0;
  1133.              }
  1134.                                      // Force newScrollPos to be a multiple
  1135.                                      //   of mScrollUnit
  1136.              newScrollPos.h = mScrollUnit.h * 
  1137.                      ((newScrollPos.h + mScrollUnit.h - 1) / mScrollUnit.h);
  1138.              
  1139.         }
  1140.         
  1141.         if ( (newScrollPos.v != currScrollPos.v) ||
  1142.              (newScrollPos.h != currScrollPos.h) ) {
  1143.             ScrollImageTo(newScrollPos.h, newScrollPos.v, inRefresh);
  1144.         }
  1145.     }
  1146. }
  1147.  
  1148.  
  1149. void
  1150. LView::SetScrollUnit(
  1151.     const SPoint32    &inScrollUnit)
  1152. {
  1153.     mScrollUnit = inScrollUnit;
  1154.     
  1155.     if (mSuperView != nil) {
  1156.         mSuperView->SubImageChanged(this);
  1157.     }
  1158. }
  1159.  
  1160.  
  1161. void
  1162. LView::GetScrollUnit(
  1163.     SPoint32    &outScrollUnit) const
  1164. {
  1165.     outScrollUnit = mScrollUnit;
  1166. }
  1167.  
  1168.  
  1169. void
  1170. LView::SubImageChanged(
  1171.     LView    *inSubView)
  1172. {
  1173. }
  1174.  
  1175.  
  1176. // ---------------------------------------------------------------------------
  1177. //        • FindSubPaneHitBy
  1178. // ---------------------------------------------------------------------------
  1179. //    Find the SubPane of this View that is hit by the specified point.
  1180. //    Return nil if no SubPane is hit
  1181. //
  1182. //    inHorizPort and inVertPort are in Port coordinates
  1183.  
  1184. LPane*
  1185. LView::FindSubPaneHitBy(
  1186.     Int32    inHorizPort,
  1187.     Int32    inVertPort)
  1188. {
  1189.     LPane    *hitSubPane = nil;
  1190.     LListIterator iterator(mSubPanes, iterate_FromEnd);
  1191.     LPane    *subPane;
  1192.     while (iterator.Previous(subPane)) {
  1193.         if (subPane->IsHitBy(inHorizPort, inVertPort)) {
  1194.             hitSubPane = subPane;
  1195.             break;
  1196.         }
  1197.     }
  1198.     
  1199.     return hitSubPane;
  1200. }
  1201.  
  1202.  
  1203. // ---------------------------------------------------------------------------
  1204. //        • Click
  1205. // ---------------------------------------------------------------------------
  1206. //    Handle a click inside a View
  1207.  
  1208. void
  1209. LView::Click(
  1210.     SMouseDownEvent    &inMouseDown)
  1211. {
  1212.                                     // Check if a SubPane of this View
  1213.                                     //   is hit
  1214.     LPane    *clickedPane = FindSubPaneHitBy(inMouseDown.wherePort.h,
  1215.                                             inMouseDown.wherePort.v);
  1216.                                             
  1217.     if (clickedPane != nil) {        // SubPane is hit, let it respond to
  1218.                                     //   the Click
  1219.         clickedPane->Click(inMouseDown);
  1220.         
  1221.     } else {                        // No SubPane hit. Inherited function
  1222.         LPane::Click(inMouseDown);    //   will process click on this View
  1223.     }
  1224. }
  1225.  
  1226.  
  1227. void
  1228. LView::AdjustCursor(
  1229.     Point                inPortPt,
  1230.     const EventRecord    &inMacEvent)
  1231. {
  1232.                                     // Check if a SubPane of this View
  1233.                                     //   contains the point
  1234.     LPane    *hitPane = FindSubPaneHitBy(inPortPt.h, inPortPt.v);
  1235.                                             
  1236.     if (hitPane != nil) {            // SubPane is hit, let it adjust the
  1237.                                     //   cursor shape
  1238.         hitPane->AdjustCursor(inPortPt, inMacEvent);
  1239.         
  1240.     } else {                        // No SubPane hit. This View adjusts
  1241.                                     //   the cursor.
  1242.         AdjustCursorSelf(inPortPt, inMacEvent);
  1243.     }
  1244. }
  1245.  
  1246.  
  1247.  
  1248. // ---------------------------------------------------------------------------
  1249. //        • FindPaneByID
  1250. // ---------------------------------------------------------------------------
  1251. //    Find the Pane of a View which has the specified ID
  1252. //
  1253. //        Searches all Panes contained within this View, not just direct
  1254. //        subpanes. Returns nil if Pane with the target ID is not found.
  1255. //
  1256.  
  1257. LPane*
  1258. LView::FindPaneByID(
  1259.     PaneIDT    inPaneID)
  1260. {
  1261.     LPane    *thePane = nil;
  1262.                                 
  1263.     if (inPaneID == mPaneID) {            // Check first if this is the one
  1264.         thePane = this;
  1265.     } else {
  1266.                                         // Search all subpanes
  1267.         LListIterator iterator(mSubPanes, iterate_FromStart);
  1268.         LPane    *theSub;
  1269.         while (iterator.Next(theSub)) {
  1270.             thePane = theSub->FindPaneByID(inPaneID);
  1271.             if (thePane != nil) break;
  1272.         }
  1273.     }
  1274.     
  1275.     return thePane;
  1276. }
  1277.  
  1278.  
  1279. Int32
  1280. LView::GetValueForPaneID(
  1281.     PaneIDT    inPaneID) const
  1282. {
  1283.     Int32    value = 0;
  1284.     LPane    *thePane = FindPaneByID(inPaneID);
  1285.     if (thePane != nil) {
  1286.         value = thePane->GetValue();
  1287.     } else {
  1288.         BreakIfDebug_("GetValue For Unknown Pane ID");
  1289.     }
  1290.     return value;
  1291. }
  1292.  
  1293.  
  1294. void
  1295. LView::SetValueForPaneID(
  1296.     PaneIDT    inPaneID,
  1297.     Int32    inValue)
  1298. {
  1299.     LPane    *thePane = FindPaneByID(inPaneID);
  1300.     if (thePane != nil) {
  1301.         thePane->SetValue(inValue);
  1302.     } else {
  1303.         BreakIfDebug_("SetValue for Unknown Pane ID");
  1304.     }
  1305. }
  1306.  
  1307.  
  1308. StringPtr
  1309. LView::GetDescriptorForPaneID(
  1310.     PaneIDT    inPaneID,
  1311.     Str255    outDescriptor) const
  1312. {
  1313.     LPane    *thePane = FindPaneByID(inPaneID);
  1314.     if (thePane != nil) {
  1315.         thePane->GetDescriptor(outDescriptor);
  1316.     } else {
  1317.         BreakIfDebug_("GetValue for Unknown Pane ID");
  1318.     }
  1319.     return outDescriptor;        
  1320. }
  1321.  
  1322.  
  1323. void
  1324. LView::SetDescriptorForPaneID(
  1325.     PaneIDT                inPaneID,
  1326.     ConstStr255Param    inDescriptor)
  1327. {
  1328.     LPane    *thePane = FindPaneByID(inPaneID);
  1329.     if (thePane != nil) {
  1330.         thePane->SetDescriptor(inDescriptor);
  1331.     } else {
  1332.         BreakIfDebug_("SetValue for Unknown Pane ID");
  1333.     }
  1334. }
  1335.  
  1336.  
  1337. // ---------------------------------------------------------------------------
  1338. //        • PortToLocalPoint
  1339. // ---------------------------------------------------------------------------
  1340. //    Convert point from Port to Local coordinates
  1341.  
  1342. void
  1343. LView::PortToLocalPoint(
  1344.     Point    &ioPoint) const
  1345. {
  1346.     ioPoint.h += mPortOrigin.h;
  1347.     ioPoint.v += mPortOrigin.v;
  1348. }
  1349.  
  1350.  
  1351. // ---------------------------------------------------------------------------
  1352. //        • LocalToPortPoint
  1353. // ---------------------------------------------------------------------------
  1354. //    Convert point from Local to Port coordinates
  1355.  
  1356. void
  1357. LView::LocalToPortPoint(
  1358.     Point    &ioPoint) const
  1359. {
  1360.     ioPoint.h -= mPortOrigin.h;
  1361.     ioPoint.v -= mPortOrigin.v;
  1362. }
  1363.  
  1364.  
  1365. // ---------------------------------------------------------------------------
  1366. //        • ImageToLocalPoint
  1367. // ---------------------------------------------------------------------------
  1368. //    Convert point from Image (32-bit) to Local (16-bit) coordinates
  1369. //
  1370. //    Image and Local coordinates are different only when the Image size
  1371. //    is greater than 16K (15-bit)
  1372.  
  1373. void
  1374. LView::ImageToLocalPoint(
  1375.     const SPoint32    &inImagePt,
  1376.     Point            &outLocalPt)
  1377. {
  1378.     outLocalPt.h = inImagePt.h + mPortOrigin.h + mImageLocation.h;
  1379.     outLocalPt.v = inImagePt.v + mPortOrigin.v + mImageLocation.v;
  1380. }
  1381.  
  1382.  
  1383. // ---------------------------------------------------------------------------
  1384. //        • LocalToImagePoint
  1385. // ---------------------------------------------------------------------------
  1386. //    Convert point from Local (16-bit) to Image (32-bit) coordinates
  1387. //
  1388. //    Image and Local coordinates are different only when the Image size
  1389. //    is greater than 16K (15-bit)
  1390.  
  1391. void
  1392. LView::LocalToImagePoint(
  1393.     const Point        &inLocalPt,
  1394.     SPoint32        &outImagePt)
  1395. {
  1396.     outImagePt.h = inLocalPt.h - mPortOrigin.h - mImageLocation.h;
  1397.     outImagePt.v = inLocalPt.v - mPortOrigin.v - mImageLocation.v;
  1398. }